package multi_thread.basic;

/**
 * Description: Java多线程系列--“基础篇”05之 线程等待与唤醒
 * https://www.cnblogs.com/skywang12345/p/3479224.html
 *
 * @author Cheng Jun
 * @version 1.0
 * @date 2019/10/29 13:18
 */
public class WaitAndNotifyExample {
    private static Object lock = new Object();

    public static void main(String[] args) {
        TestNotifyThread t1 = new TestNotifyThread("t1");
        //获取 lock对象的同步锁
        synchronized (lock) {
            System.out.println(Thread.currentThread().getName() + " start t1");
            t1.start();
            try {
                System.out.println(Thread.currentThread().getName() + " wait()");
                // 请看 Object.java 的源码注释
                // 调用了wait系列方法会释放锁，别的线程（正在等待 lock对象锁的线程）才能竞争。
                // wait() 释放锁，当前线程阻塞，一直等待被通知
                // lock.wait();
                // wait(4_000) 释放锁，当前线程阻塞，一直等待被通知，或者在 4_000 毫秒后尝试获取锁，如果此时锁被别的线程持有，就无法获取到
                lock.wait(4_000);
                System.out.println(Thread.currentThread().getName() + " continue");
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }

        // TestNotifyAllThread testNotifyAllThread1 = new TestNotifyAllThread("testNotifyAllThread1");
        // TestNotifyAllThread testNotifyAllThread2 = new TestNotifyAllThread("testNotifyAllThread2");
        // testNotifyAllThread1.start();
        // testNotifyAllThread2.start();
        //
        // try {
        //     System.out.println(Thread.currentThread().getName() + "sleep 2 秒，以便TestNotifyAllThread的对象执行完 lock.wait 语句");
        //     Thread.sleep(2000);
        // } catch (InterruptedException e) {
        //     e.printStackTrace();
        // }
        //
        // synchronized (lock){
        //     System.out.println(Thread.currentThread().getName() + "唤醒所有在lock对象监视器上的等待线程");
        //     lock.notifyAll();
        // }
    }

    static class TestNotifyThread extends Thread {

        public TestNotifyThread(String name) {
            super(name);
        }

        @Override
        public void run() {
            synchronized (lock) {
                System.out.println(Thread.currentThread().getName() + " notify()");
                // notify 并不会立刻释放 lock对象锁，必须等 synchronized 代码块 执行完，才会释放lock对象锁，
                lock.notify();
                try {
                    Thread.sleep(5_000);
                    System.out.println(Thread.currentThread().getName() + "继续执行完");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    // 通常，在finally 语法块中，释放锁。这样可以避免死锁
                    // lock.notify();
                }
            }
        }
    }

    static class TestNotifyAllThread extends Thread {

        public TestNotifyAllThread(String name) {
            super(name);
        }

        @Override
        public void run() {
            synchronized (lock) {
                System.out.println(Thread.currentThread().getName() + " wait()");
                try {
                    lock.wait();
                    // Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " run over");
            }
        }
    }

}
